//! ProtoActor - Ultra-fast distributed actors for Rust
//!
//! This crate provides an implementation of the Actor model for Rust,
//! based on the design of ProtoActor-Go.

pub mod actor;
pub mod process;
pub mod system;
pub mod mailbox;
pub mod dispatcher;
pub mod dispatcher_enum;
pub mod supervision;
pub mod supervision_enum;
pub mod supervision_event;
pub mod supervision_tree;
pub mod streaming;
pub mod middleware;
pub mod remote;
// pub mod cluster;
pub mod persistence;
pub mod telemetry;

pub use actor::{
    Actor, ActorContext, DefaultActorContext, PID, Props,
    ActorError, Message, Responder, SpawnError, SystemMessage,
    SupervisorStrategy, SupervisorDirective,
};

pub use process::{Process, ProcessRegistry};
pub use system::{ActorSystem, ActorSystemConfig};
pub use mailbox::{Mailbox, MessageInvoker};
pub use dispatcher::{Dispatcher, Dispatchers};

// Re-export remote types
pub use remote::{
    Remote,
    RemoteConfig,
    RemoteError,
};

// Re-export supervision types
pub use supervision::{
    RestartStatistics,
    Supervisor,
    one_for_one,
    all_for_one,
    exponential_backoff,
};

// Re-export generated protobuf code
pub mod protos {
    pub mod actor {
        include!(concat!(env!("OUT_DIR"), "/actor.rs"));
    }
    
    pub mod remote {
        include!(concat!(env!("OUT_DIR"), "/remote.rs"));
    }
    
    pub mod cluster {
        include!(concat!(env!("OUT_DIR"), "/cluster.rs"));
    }
}

// Initialize logging
pub fn init_logging() {
    use tracing::{Level, Subscriber};
    use tracing_subscriber::FmtSubscriber;
    use tracing_subscriber::prelude::*;
    
    let subscriber = FmtSubscriber::builder()
        .with_max_level(Level::DEBUG)
        .with_target(false)
        .with_thread_ids(true)
        .with_thread_names(true)
        .with_file(true)
        .with_line_number(true)
        .with_ansi(true)
        .with_env_filter("debug")
        .pretty()
        .try_init();
    
    if let Err(e) = subscriber {
        eprintln!("Failed to initialize logging: {}", e);
    }
}

/// Logging utilities for the ProtoActor crate
pub mod logging {
    use tracing::{trace, debug, info, warn, error, span, Level};
    
    /// Initialize the global logger with optional level and filter
    pub fn init_global_logger(level: Option<tracing::Level>, filter: Option<&str>) -> Result<(), String> {
        let subscriber = tracing_subscriber::FmtSubscriber::builder()
            .with_max_level(level.unwrap_or(tracing::Level::INFO))
            .with_target(false)
            .with_thread_ids(true)
            .with_thread_names(true)
            .with_file(true)
            .with_line_number(true)
            .with_ansi(true)
            .with_env_filter(filter.unwrap_or("debug"))
            .pretty();
            
        match subscriber.try_init() {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("Failed to initialize logging: {}", e)),
        }
    }
    
    /// Log a message at the INFO level
    pub fn info_system(system: &str, message: impl std::fmt::Display) {
        info!(target: "system", system = system, "{}", message);
    }
    
    /// Log a message at the DEBUG level
    pub fn debug_system(system: &str, message: impl std::fmt::Display) {
        debug!(target: "system", system = system, "{}", message);
    }
    
    /// Log a message at the WARN level
    pub fn warn_system(system: &str, message: impl std::fmt::Display) {
        warn!(target: "system", system = system, "{}", message);
    }
    
    /// Log a message at the ERROR level
    pub fn error_system(system: &str, message: impl std::fmt::Display) {
        error!(target: "system", system = system, "{}", message);
    }
    
    /// Log a message at the TRACE level
    pub fn trace_system(system: &str, message: impl std::fmt::Display) {
        trace!(target: "system", system = system, "{}", message);
    }
}

/// Logging utility functions for internal use
pub(crate) mod log_utils {
    use tracing::{trace, debug, info, warn, error, span, Level};
    use std::fmt::Debug;

    /// Log a trace message with a consistent format for system events
    /// 
    /// # Parameters
    /// 
    /// * `component` - The system component generating the log (e.g., "ActorSystem", "Mailbox")
    /// * `message` - The message to log
    pub fn trace_system<M: Debug>(component: &str, message: M) {
        trace!(target: "protoactor_rs.system", component = component, "{:#?}", message);
    }

    /// Log a debug message with a consistent format for system events
    pub fn debug_system<M: Debug>(component: &str, message: M) {
        debug!(target: "protoactor_rs.system", component = component, "{:#?}", message);
    }

    /// Log an info message with a consistent format for system events
    pub fn info_system<M: Debug>(component: &str, message: M) {
        info!(target: "protoactor_rs.system", component = component, "{:#?}", message);
    }

    /// Log a warning message with a consistent format for system events
    pub fn warn_system<M: Debug>(component: &str, message: M) {
        warn!(target: "protoactor_rs.system", component = component, "{:#?}", message);
    }

    /// Log an error message with a consistent format for system events
    pub fn error_system<M: Debug>(component: &str, message: M) {
        error!(target: "protoactor_rs.system", component = component, "{:#?}", message);
    }

    /// Log a message for an actor operation
    pub fn trace_actor<M: Debug>(actor_type: &str, message: M) {
        trace!(target: "protoactor_rs.actor", actor_type = actor_type, "{:#?}", message);
    }

    /// Log a debug message for an actor operation
    pub fn debug_actor<M: Debug>(actor_type: &str, message: M) {
        debug!(target: "protoactor_rs.actor", actor_type = actor_type, "{:#?}", message);
    }

    /// Log an info message for an actor operation 
    pub fn info_actor<M: Debug>(actor_type: &str, message: M) {
        info!(target: "protoactor_rs.actor", actor_type = actor_type, "{:#?}", message);
    }

    /// Log a warning message for an actor operation
    pub fn warn_actor<M: Debug>(actor_type: &str, message: M) {
        warn!(target: "protoactor_rs.actor", actor_type = actor_type, "{:#?}", message);
    }

    /// Log an error message for an actor operation
    pub fn error_actor<M: Debug>(actor_type: &str, message: M) {
        error!(target: "protoactor_rs.actor", actor_type = actor_type, "{:#?}", message);
    }

    /// Log a message related to messaging
    pub fn trace_msg<M: Debug>(message_type: &str, message: M) {
        trace!(target: "protoactor_rs.messaging", message_type = message_type, "{:#?}", message);
    }

    /// Log a debug message related to messaging
    pub fn debug_msg<M: Debug>(message_type: &str, message: M) {
        debug!(target: "protoactor_rs.messaging", message_type = message_type, "{:#?}", message);
    }

    /// Log an info message related to messaging
    pub fn info_msg<M: Debug>(message_type: &str, message: M) {
        info!(target: "protoactor_rs.messaging", message_type = message_type, "{:#?}", message);
    }

    /// Log a warning message related to messaging
    pub fn warn_msg<M: Debug>(message_type: &str, message: M) {
        warn!(target: "protoactor_rs.messaging", message_type = message_type, "{:#?}", message);
    }

    /// Log an error message related to messaging
    pub fn error_msg<M: Debug>(message_type: &str, message: M) {
        error!(target: "protoactor_rs.messaging", message_type = message_type, "{:#?}", message);
    }
    
    /// Log a message for a traced operation with a specific trace ID
    pub fn trace_op<M: Debug>(trace_id: &str, message: M) {
        trace!(trace_id = trace_id, "{:#?}", message);
    }

    /// Log a debug message for a traced operation
    pub fn debug_op<M: Debug>(trace_id: &str, message: M) {
        debug!(trace_id = trace_id, "{:#?}", message);
    }

    /// Log an info message for a traced operation
    pub fn info_op<M: Debug>(trace_id: &str, message: M) {
        info!(trace_id = trace_id, "{:#?}", message);
    }

    /// Log a warning message for a traced operation
    pub fn warn_op<M: Debug>(trace_id: &str, message: M) {
        warn!(trace_id = trace_id, "{:#?}", message);
    }

    /// Log an error message for a traced operation
    pub fn error_op<M: Debug>(trace_id: &str, message: M) {
        error!(trace_id = trace_id, "{:#?}", message);
    }

    /// Create a span for a traced operation
    pub fn span_op(name: &str, trace_id: &str) -> tracing::Span {
        tracing::span!(Level::TRACE, "operation", trace_id = trace_id.to_string())
    }

    /// Create a span for a system operation
    pub fn span_system(name: &str, component: &str) -> tracing::Span {
        tracing::span!(target: "protoactor_rs.system", Level::TRACE, "system", component = component.to_string())
    }

    /// Create a span for an actor operation
    pub fn span_actor(name: &str, actor_type: &str) -> tracing::Span {
        tracing::span!(target: "protoactor_rs.actor", Level::TRACE, "actor", actor_type = actor_type.to_string())
    }

    /// Create a span for a messaging operation
    pub fn span_msg(name: &str, message_type: &str) -> tracing::Span {
        tracing::span!(target: "protoactor_rs.messaging", Level::TRACE, "messaging", message_type = message_type.to_string())
    }

    /// Create a span for a supervision operation
    pub fn span_supervision(name: &str, strategy: &str) -> tracing::Span {
        tracing::span!(target: "protoactor_rs.supervision", Level::TRACE, "supervision", strategy = strategy.to_string())
    }
}

/// Create a simple example to demonstrate usage
#[cfg(test)]
mod tests {
    use std::time::Duration;
    use std::any::Any;
    use async_trait::async_trait;
    use tracing::info;
    use super::*;
    
    #[tokio::test]
    async fn test_basic_actor() {
        // Initialize the logger
        logging::init_global_logger(Some(tracing::Level::INFO), None).unwrap();
        
        // Create an actor system
        let system = ActorSystem::new().unwrap();
        
        // Define a simple actor
        struct HelloActor;
        
        #[async_trait]
        impl Actor for HelloActor {
            type Context = actor::DefaultActorContext;
            
            async fn receive(&self, ctx: &mut Self::Context, msg: Box<dyn Any + Send>) -> Result<(), ActorError> {
                // Try to downcast the message to a string
                if let Ok(message) = msg.downcast::<String>() {
                    info!("Received: {}", message);
                    
                    // If the message is "hello", respond with "world"
                    if message.as_str() == "hello" {
                        ctx.respond("world".to_string());
                    }
                }
                
                Ok(())
            }
        }
        
        // Create props for the actor
        let props = Props::new(|| Box::new(HelloActor));
        
        // Spawn the actor
        let pid = system.spawn::<HelloActor>(props).await.unwrap();
        
        // Send a message to the actor
        system.send(&pid, "hello".to_string()).await.unwrap();
        
        // Wait a bit for the message to be processed
        tokio::time::sleep(Duration::from_millis(100)).await;
        
        // Stop the actor
        system.stop(&pid).await.unwrap();
        
        // 等待一段时间，确保actor已经停止
        tokio::time::sleep(Duration::from_millis(100)).await;
        
        // 我们不需要显式关闭ActorSystem，它会在测试结束时自动关闭
        // 由于我们修改了Drop实现，它不会在异步上下文中尝试丢弃运行时
    }
}

#[cfg(target_arch = "wasm32")]
pub mod wasm;

#[cfg(target_arch = "wasm32")]
pub use wasm::*;

// 从一些模块中导出公共类型方便使用
// pub use actor::PID;
// pub use actor::Props;
// pub use actor::ActorContext;
// pub use actor::ActorError;
pub use dispatcher::DispatcherTrait; 